#include <memory.h>
#include "../Headers/config.h"
#include "../Headers/log.h"
#include "authorization.h"

#include <iostream>


// Constructor
TOB::Authorization::Authorization(TOB::Nameserver::IP nsip, std::string username, std::string password): AuthRequired(nsip, username, password) {
  Nameserver::IP ip;
  std::string addr;
  connected = false;

  Nameserver::convertIP(nsip, addr);
  Nameserver ns(addr);
  if(ns.requestAddress(Server::Authorization, ip) != Code::Okay) { return; }
  Nameserver::convertIP(ip, addr);
  
// connect to server
  clnt = clnt_create(addr.c_str(), AR_PROG, AR_VER, "udp");
  if(clnt == NULL) { return; }
  connected = true;
}


// Destructor
TOB::Authorization::~Authorization() {
  if (clnt != NULL && connected) {
    clnt_destroy(clnt);
  }
}


// User management 
Code::Type TOB::Authorization::UserManagement(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowUserManagement, result);
}

// Email 
Code::Type TOB::Authorization::Email(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowMail, result);
}

// FileSharing 
Code::Type TOB::Authorization::FileSharing(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowFileSharing, result);
}

// ToDoList 
Code::Type TOB::Authorization::ToDoList(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowToDo, result);
}

// Calendar 
Code::Type TOB::Authorization::Calendar(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowCalendar, result);
}

// CatalogRecordEdit 
Code::Type TOB::Authorization::DirectoryRecordEdit(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowDirectory, result);
}

// Time
Code::Type TOB::Authorization::Time(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowTime, result);
}

// WebServer 
Code::Type TOB::Authorization::WebServer(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getPolicy(Policy::AllowWebServer, result);
}

// CatalogFieldEdit priv
Code::Type TOB::Authorization::DirectoryFieldEdit(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getRole(Role::Administrator, result);
}

// User management priv
Code::Type TOB::Authorization::UserManagementPriv(bool &result) {
  if(!connected) { return Code::AR_DoesntRespond; }
  return getRole(Role::Administrator, result);
}


// Request policy from AR
Code::Type TOB::Authorization::getPolicy(Policy::Type policy, bool &out) {
  if(!connected) { return Code::AR_DoesntRespond; }
  result *res;
  policyParam param;
  param.req.nsip = nsip;
  cutAndPaste(param.req.username, username);
  cutAndPaste(param.req.password, password);
  param.param = policy;
  res = checkpolicy_1(&param, clnt);
  if(res == NULL) { return Code::AR_DoesntRespond; }
  if(res->code != Code::Okay) 
  { return static_cast<Code::Type>(res->code); } 
  out = res->result;
  return Code::Okay;
}


// Request role from AR
Code::Type TOB::Authorization::getRole(Role::Type role, bool &out) {
  if(!connected) { return Code::AR_DoesntRespond; }
  result *res;
  roleParam param;
  param.req.nsip = nsip;
  cutAndPaste(param.req.username, username);
  cutAndPaste(param.req.password, password);
  param.param = role;
  res = checkrole_1(&param, clnt);
  if(res == nullptr) { return Code::AR_DoesntRespond; }
  if(res->code != Code::Okay) 
    { return static_cast<Code::Type>(res->code); } 
  out = res->result;
  return Code::Okay;
}


// Cut and paste
void TOB::Authorization::cutAndPaste(char *dest, std::string &source,
   uint32 length) {
  uint32 size = source.size() + 1;
  if(size > length) {
    size = length;
    dest[size] = 0;
  }
  memcpy(dest, source.c_str(), size);
}
